package com.lzw.DailyAudit.service.dateAggregation_02.DailyAudit.service.dealSourceData_01;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.hooya.fa.eu.api.bo.stk.BuyRecordBO;
import com.hooya.fa.eu.api.bo.stk.HistoryBelongsBO;
import com.hooya.fa.eu.api.bo.stk.ReturnedRecordBO;
import com.hooya.fa.eu.api.bo.stk.SellRecordBO;
import com.hooya.fa.eu.api.enums.CkEnum;
import com.hooya.fa.eu.biz.DailyAudit.entity.DailyAuditStatus;
import com.hooya.fa.eu.biz.DailyAudit.mapper.DailyAuditStatusMapper;
import com.hooya.fa.eu.biz.DailyAudit.service.dateAggregation_02.CommonService;
import com.hooya.fa.eu.biz.dao.entity.*;
import com.hooya.fa.eu.biz.dao.entity.rxh.MetaStore;
import com.hooya.fa.eu.biz.dao.manager.AddEntityManager;
import com.hooya.fa.eu.biz.dao.manager.DictManager;
import com.hooya.fa.eu.biz.dao.manager.PkManager;
import com.hooya.fa.eu.biz.dao.manager.special.*;
import com.hooya.fa.eu.biz.dao.mapper.*;
import com.hooya.fa.eu.biz.service.DictRelationService;
import com.hooya.fa.eu.biz.service.EuSourceDataService;
import com.hooya.fa.eu.biz.service.OrderEuService;
import com.hooya.fa.eu.biz.service.TempRelationService;
import com.hooya.fa.eu.biz.service.impl.StkCollectionServiceImpl;
import com.hooya.integrated.common.core.util.BeanCopyUtils;
import com.hooya.integrated.common.core.util.RedisUtils;
import com.hooya.integrated.common.util.times.DateExtUtil;
import com.xxl.job.core.context.XxlJobHelper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.hooya.fa.eu.api.constant.DictConstant.DICT_PREFIX;

/**
 * @Description 1
 * @Author : Zongz
 * @Copyright Copyright (c) 豪雅集团
 * @Create 2024/1/29
 * @Version 1.0.0
 */
@Slf4j
@Service
@DS("fa_eu")
@AllArgsConstructor
public class DailyStkCollectionService {

	private final static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");

	private final EuSourceDataService euSourceDataService;

	private final StkBuyMapper stkBuyMapper;

	private final TempRelationService tempRelationService;

	private final DictRelationService dictRelationService;

	private final OrderEuService orderEuService;

	private final JcDataManager jcDataManager;

	private final SellDeliveryManager sellDeliveryManager;

	private final ReturnedGoodsManager returnedGoodsManager;

	private final JcHisBelongsManager jcHisBelongsManager;

	private final XsDataManager xsDataManager;

	private final FinalDataManager finalDataManager;

	private final DictManager dictManager;

	private final CkDictMapper dictMapper;

	private final AddEntityManager entityManager;

	private final PkManager pkManager;

	private final StkSellMapper stkSellMapper;

	private final StkCollectionServiceImpl stkCollectionService;

	private final DailyAuditStatusMapper statusMapper;

	private final CommonService commonService;

	public void generatorCollectionData(String startDate, String endDate, int num) {

		String name = "generatorCollectionData-01";
		DailyAuditStatus dailyAuditStatus = statusMapper.selectStatus(name, startDate);
		if(dailyAuditStatus != null && dailyAuditStatus.getFlag() == 1){
			log.info("{} - 该方法已执行，进行跳过！",name);
			return;
		}

		log.info("开始执行Stk审计数据插入任务");

		//仓库数据（库存）
		String yesterday = DateExtUtil.getYesterday(startDate);
		List<TempKcjlDaily> inventoryList = tempRelationService.getOpeningInventory(yesterday, null)
				.stream().filter(l -> !l.getPlace().equals("EU07")).collect(Collectors.toList());
		//------------------------------------ 各个字典 ------------------------------------
		//fba国家列表
		List<String> fbaCountryList = euSourceDataService.getFbaCountryList();
		//虚拟仓库字典
		List<PlaceMatchDict> placeMatchDictList = dictRelationService.getPlaceMatchList();
		Map<String, PlaceMatchDict> placeMatchDictMap = placeMatchDictList.stream()
				.collect(Collectors.toMap(PlaceMatchDict::getVirtualWhId, i -> i));
		//店铺公司字典
		List<MetaStore> metaStoreList = dictRelationService.getMetaStoreList();
		Map<String, String> storeMap = metaStoreList.stream().
				collect(Collectors.toMap(l -> l.getStore().toLowerCase(), MetaStore::getCorp));
		//进仓公司字典
		Map<String, String> metaWarehouseMap = dictRelationService.getMetaWarehouseMap();
		//其他仓库字典
		List<CkDict> dictList = dictMapper.selectList(null);
		dictManager.cacheDict(dictList);

		Map<String, String> fbaCkMap = RedisUtils.hmget(DICT_PREFIX + CkEnum.FBA_CK_MAP.getName());

		//平仓
		List<TempPkpy> closePositionPkpyList = pkManager.closePosition(yesterday, startDate, inventoryList);
		inventoryList = inventoryList.stream().filter(l -> l.getSl() != 0).collect(Collectors.toList());

		//补单开始时间与补单日期
		String suppStartDate = DateExtUtil.getBeforeNMonthFirstDay(
				LocalDate.parse(startDate, DateTimeFormatter.ISO_LOCAL_DATE), num == 0 ? 1 : num);
		String suppDate = DateExtUtil.getCurMonthLastDay(LocalDate.parse(startDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")));  // 做修改 时间 设置为 本月底 - 最后一天

		//------------------------------------ 进仓 ------------------------------------
		List<BuyRecordBO> recordList = new LinkedList<>();
		//所有进仓记录（本月 + 历史）
//		List<BuyRecordBO> warehousingList = euSourceDataService.getWarehousingListByDate(null, null);  //TODO  -  默认使用这个是正确的  但是测试的话，那数据应该是 当天之前  这里的变换应该能够解决货权问题
		List<BuyRecordBO> warehousingList = stkBuyMapper.getWarehousingListByDateDaily(startDate);
		//warehousingList进仓数据的处理
		jcDataManager.dealSourceJcData(df, warehousingList, recordList, placeMatchDictMap);
		//取出本月进仓数据
		List<BuyRecordBO> monthWarehousingList = jcDataManager.getCurMonthJcData(df, startDate, endDate, recordList);
		//------------------------------------ 转运 ------------------------------------
		//24年5月开始将EU07仓库全部转出，所以需要将转入和转出到该仓库的数据除去
		List<BuyRecordBO> zyList = euSourceDataService.getZyListByDate(startDate, endDate);
		zyList.forEach(f -> f.setHthm(f.getHthm() != null ? f.getHthm() + "-" + startDate.split("-")[2] : ""));
		//转运补单数据(获取除盘亏盘盈差异意外的)
		List<BuyRecordBO> hisSupplementZyList = euSourceDataService.getSupplementZyList(suppStartDate, startDate);
		List<TempPkpy> hisPkpyList = tempRelationService.getPkpyListByDate(suppStartDate, startDate);
		List<BuyRecordBO> removeZyList = new LinkedList<>();
		if (!CollectionUtils.isEmpty(hisSupplementZyList)) {    // 相当于转运补单记录 如果存在 于 盘亏盘盈则删除 说明已经补过单了
			for (BuyRecordBO bo : hisSupplementZyList) {
				List<TempPkpy> pkpies = hisPkpyList.stream().filter(l -> l.getCpbh().equals(bo.getCpbh())
						&& l.getPlace().equals(bo.getZcck()) && Objects.equals(l.getSl(), bo.getCgsl())
						&& l.getDate().equals(bo.getHtrq())).collect(Collectors.toList());
				if (!CollectionUtils.isEmpty(pkpies)) {
					removeZyList.add(bo);
				}
			}
			hisSupplementZyList.removeAll(removeZyList);
			hisSupplementZyList.forEach(l -> l.setHtrq(suppDate));
			zyList.addAll(hisSupplementZyList);
			List<BuyRecordBO> suppSzkList = hisSupplementZyList.stream()
					.filter(l -> l.getZcck().equals("EU生资库")).collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(suppSzkList)) {
				log.info("转运补单生资库，数据为：" + suppSzkList);
			}
			log.info("所有补充转运单的合同日期：" + suppDate + ",合同号码为：" +
					hisSupplementZyList.stream().map(BuyRecordBO::getHthm).distinct().collect(Collectors.toList()));
		}

		//------------------------------------ 销售发货前处理lywl为FDS_return的数据 ------------------------------------
		String name1 = "insertLywlIsFbaReturn-01";
		DailyAuditStatus dailyAuditStatus1 = statusMapper.selectStatus(name1, startDate);
		if (dailyAuditStatus1 != null && dailyAuditStatus1.getFlag() == 1) {
			log.info("{} - 该方法已执行，进行跳过！", name1);
		} else {
			List<SellRecordBO> sellRecordBOS = stkSellMapper.getlywlIsFbaReturnListDaily(startDate, endDate);
			if (!sellRecordBOS.isEmpty()) {
				sellRecordBOS.forEach(sellRecordBO -> sellRecordBO.setCompany(storeMap.get(sellRecordBO.getDianPu())));
				List<TempXsjlAbnormal> tempXsjlAbnormalLywlIsFDS_ReturnList = sellRecordBOS.stream()
						.map(sellRecordBO ->
								BeanCopyUtils.copyPropertiesNew(sellRecordBO,
										TempXsjlAbnormal::new, (s, t) -> {
											t.setCreateTime(new Date());
										})
						)
						.collect(Collectors.toList());
				log.info("开始执行FbaReturnToXsjlAbnormal");
				stkSellMapper.insertLywlIsFbaReturnDaily(tempXsjlAbnormalLywlIsFDS_ReturnList);
				// 修改执行状态
				commonService.UpdateOrInsertStatus(dailyAuditStatus1, name1, startDate);
				log.info("FbaReturnToXsjlAbnormal执行完成");
			}
		}
		//------------------------------------ 销售发货 ------------------------------------

		List<SellRecordBO> sellDeliveryList = sellDeliveryManager
				.getSellDeliveryListByDate(startDate, endDate, placeMatchDictMap, storeMap, fbaCountryList);
		//销售补单数据
		List<SellRecordBO> hisSellDeliveryList = sellDeliveryManager
				.getHisSellDeliveryListByDate(suppStartDate, startDate, placeMatchDictMap, storeMap, fbaCountryList);
		if (!CollectionUtils.isEmpty(hisSellDeliveryList)) {
			log.info("销售补充数据有" + hisSellDeliveryList.size() + "条");
			hisSellDeliveryList.forEach(l -> l.setOrderDate(suppDate));
			sellDeliveryList.addAll(hisSellDeliveryList);
		}
		//校验移除销售发货已存在历史销售记录的数据
		sellDeliveryManager.checkSheetNumberDaily(sellDeliveryList,startDate);

				//------------------------------------ 退货 ------------------------------------
		List<String> returnedOrderIds = orderEuService.getReturnedOrderIdsByDate(startDate, endDate);
		List<ReturnedRecordBO> returnedList =
				euSourceDataService.getReturnedListByDate(startDate, endDate, returnedOrderIds);
		List<ReturnedRecordBO> resReturnedList = returnedGoodsManager.
				getEligibleReturnGoodsData(returnedList, placeMatchDictMap, storeMap);


		//修改历史进仓货权，并整合数据
		List<HistoryBelongsBO> allHisBelongsList =
				jcHisBelongsManager.editJcHisBelongsAndIntegration(recordList);
		//fba货权信息(做筛选优化用)
		List<HistoryBelongsBO> fbaBelongsList =
				jcHisBelongsManager.getFbaJcHisBelongsData(df, startDate, allHisBelongsList, fbaCkMap);

		//------------------------------------ 新增结果集 ------------------------------------
		//总的进仓记录
		List<TempJcjl> finalTempJcjlList = new LinkedList<>();
		//总的转运记录
		List<TempZyjl> finalTempZyjlList = new LinkedList<>();
		//总的仓库记录
		List<TempKcjlDaily> allInventoryList = new LinkedList<>();
		//总的买卖记录
		List<TradeRecord> finalTradeRecordList = new LinkedList<>();
		//盘亏盘盈集合
		List<TempPkpy> finalPkpyList = new LinkedList<>(closePositionPkpyList);
		List<TempThjl> finalTempThjlList = new LinkedList<>();
		List<TempXsjl> finalTempXsjlList = new LinkedList<>();
		List<TempXsjlAbnormal> finalTempXsjlAbnormalList = new LinkedList<>();
		List<TempXsjlDelete> finalTempXsjlDeleteList = new LinkedList<>();
		List<TempZyjlDelete> finalTempZyjlDeleteList = new ArrayList<>();
		List<TempZyjlChange> finalZyjlChangeList = new LinkedList<>();

		//==================================== 当月循环,整理数据 ====================================
		Date start = new Date(startDate.replace("-", "/"));
		Date end = new Date(endDate.replace("-", "/"));
		DateRange dateRange = DateUtil.range(start, end, DateField.DAY_OF_MONTH);
		Map<String, List<BuyRecordBO>> jcMap = monthWarehousingList.stream().collect(Collectors.groupingBy(BuyRecordBO::getHtrq));
		Map<String, List<BuyRecordBO>> zyMap = zyList.stream().collect(Collectors.groupingBy(BuyRecordBO::getHtrq));
		List<BuyRecordBO> fbaHisJcZy = BeanCopyUtils.copyListProperties(fbaBelongsList, BuyRecordBO::new);
		//fds公司删除订单计数
		AtomicInteger deleteFdsXsjl = new AtomicInteger(0);
		//其他
		Date createTime = new Date();
		long st = System.currentTimeMillis();
		for (DateTime time : dateRange) {
			String curDate = time.toDateStr();
			//边界控制
			if (curDate.equals(endDate)) {
				continue;
			}
			log.info(curDate);
			XxlJobHelper.log(curDate);
			//需要进行删除的转运数据(转运中，库存不存在，进仓不存在，转运中转入不存在（非fba逻辑）)
			List<TempZyjlDelete> tempZyjlDeleteList = new ArrayList<>();
			//总的买卖记录
			List<TradeRecord> tradeRecordList = new LinkedList<>();
			//总的进仓记录
			List<TempJcjl> tempJcjlList = new LinkedList<>();
			//总的转运记录
			List<TempZyjl> tempZyjlList = new LinkedList<>();
			//变更的转运记录(每轮循环结束，将相同条件合并，数量相加，以防万一)
			List<TempZyjlChange> zyjlChangeList = new LinkedList<>();
			List<BuyRecordBO> deleteZyRecord = new LinkedList<>();
			//盘亏盘盈集合
			List<TempPkpy> pkpyList = new LinkedList<>();

			//------------------------------------ 处理进仓转运数据 ------------------------------------
			stkCollectionService.dealWithJcZyData(curDate, fbaCkMap, jcMap, zyMap, inventoryList, tradeRecordList, tempJcjlList,
					tempZyjlList, zyjlChangeList, fbaHisJcZy, metaWarehouseMap, deleteZyRecord, pkpyList);
			if (!CollectionUtils.isEmpty(deleteZyRecord)) {
				tempZyjlDeleteList.addAll(BeanCopyUtils.copyListProperties(deleteZyRecord, TempZyjlDelete::new));
			}
			//进仓加入所有历史货权
			if (!CollectionUtils.isEmpty(tempJcjlList)) {
				List<HistoryBelongsBO> jcHisList = BeanCopyUtils
						.copyListProperties(tempJcjlList, HistoryBelongsBO::new, (s, t) -> t.setType("海运"));
				allHisBelongsList.addAll(jcHisList);
			}
			//转运加入所有历史货权
			if (!CollectionUtils.isEmpty(tempZyjlList)) {
				tempZyjlList = tempZyjlList.stream().filter(l -> l.getCgsl() != 0).collect(Collectors.toList());
				List<HistoryBelongsBO> zyHisList = BeanCopyUtils
						.copyListProperties(tempZyjlList, HistoryBelongsBO::new, (s, t) -> {
							t.setPlace(s.getZlck());
							t.setBelongs(s.getTobelongs());
							t.setType("转运");
						});
				allHisBelongsList.addAll(zyHisList);
			}
			List<HistoryBelongsBO> newAllHisBelongsList = allHisBelongsList.stream().distinct()
					.collect(Collectors.toList());
			//------------------------------------ 处理销售数据 ------------------------------------
			List<TempThjl> tempThjlList = new LinkedList<>();
			List<TempXsjl> tempXsjlList = new LinkedList<>();
			List<TempXsjlAbnormal> tempXsjlAbnormalList = new LinkedList<>();
			//当日需要处理的销售数据
			List<SellRecordBO> curSellData = sellDeliveryManager
					.dealCurSellDelivery(curDate, sellDeliveryList, newAllHisBelongsList);
			//销售区分fba、非fba数据
			List<HistoryBelongsBO> hisCkBelongsList = newAllHisBelongsList.stream()
					.filter(l -> {
						try {
							long dateTime = df.parse(l.getHtrq()).getTime();
							if (dateTime < df.parse(curDate).getTime()) {
								return true;
							}
						} catch (Exception e) {
							throw new RuntimeException(e.getMessage() + ",时间格式化失败！htrq：" + l.getHtrq());
						}
						return false;
					})
					.collect(Collectors.toList());
			//非fba所有历史货权信息
			List<HistoryBelongsBO> hisBelongList = hisCkBelongsList.stream()
					.filter(l -> StringUtils.isBlank(fbaCkMap.get(l.getPlace())))
					.collect(Collectors.toList());
			//fba
			List<HistoryBelongsBO> fbaHisBelongList = hisCkBelongsList.stream()
					.filter(l -> StringUtils.isNotBlank(fbaCkMap.get(l.getPlace())))
					.collect(Collectors.toList());
			xsDataManager.dealWithSellData(curDate, curSellData, hisBelongList, inventoryList,
					resReturnedList, metaWarehouseMap, tempThjlList, tempXsjlList);
			if (!CollectionUtils.isEmpty(tempThjlList)) {
				List<HistoryBelongsBO> thjl = BeanCopyUtils
						.copyListProperties(tempThjlList, HistoryBelongsBO::new, (s, t) -> {
							t.setHtrq(curDate);
							t.setType("退货");
						});
				newAllHisBelongsList.addAll(thjl);
			}
			xsDataManager.deductSellData(curSellData, hisBelongList, fbaHisBelongList, inventoryList,
					tempXsjlList, tradeRecordList, tempXsjlAbnormalList, metaWarehouseMap, deleteFdsXsjl);
			List<TempXsjlDelete> tempXsjlDeleteList = new LinkedList<>();
			List<TempKcjlDaily> turnPkpyRes = new ArrayList<>();
			List<TempKcjlDaily> allMinusInventoryList = inventoryList.stream().filter(l -> l.getSl() < 0)
					.collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(allMinusInventoryList)) {
				turnPkpyRes.addAll(allMinusInventoryList);
				//盘亏盘盈入库
				pkpyList.addAll(BeanCopyUtils.copyListProperties(allMinusInventoryList, TempPkpy::new));
			}
			//进仓转运和
			finalDataManager.dealJcZyThenPkpy(tempJcjlList, tempZyjlList, turnPkpyRes, inventoryList, pkpyList);
			finalDataManager.dealFinalData(curDate, inventoryList, allInventoryList, tempXsjlList, tradeRecordList,
					tempXsjlAbnormalList, tempXsjlDeleteList);
			String dataDailyLog = "进仓：" + tempJcjlList.size() + ",仓库：" + inventoryList.size() + ",买卖：" + tradeRecordList.size() +
					",盘亏盘盈：" + pkpyList.size() + ",退货：" + tempThjlList.size() + ",销售：" + tempXsjlList.size() +
					",销售abnormal：" + tempXsjlAbnormalList.size() + ",销售delete：" + tempXsjlDeleteList.size() +
					",转运delete：" + tempZyjlDeleteList.size() + ",转运：" + tempZyjlList.size() +
					",转运change：" + zyjlChangeList.size() + ",删除销售单阈值：" + deleteFdsXsjl.get();
			log.info(dataDailyLog);
			XxlJobHelper.log(dataDailyLog);
			entityManager.dealDateRelation4Data(createTime, curDate, tempJcjlList, tempXsjlList, tempThjlList,
					tempZyjlList, tradeRecordList, pkpyList, tempXsjlAbnormalList, tempXsjlDeleteList,
					tempZyjlDeleteList, finalTempJcjlList, finalTempXsjlList, finalTempThjlList, finalTempZyjlList,
					finalTradeRecordList, finalPkpyList, finalTempXsjlAbnormalList, finalTempXsjlDeleteList,
					finalTempZyjlDeleteList, finalZyjlChangeList, zyjlChangeList, allInventoryList);
		}
		//新增数据
		String executeTimeLog = "转运进仓、销售（无盘亏盘盈） 执行总用时为：" + (System.currentTimeMillis() - st) / 1000 + "s";
		log.info(executeTimeLog);
		XxlJobHelper.log(executeTimeLog);
		//新增数据
		long addT = System.currentTimeMillis();
		entityManager.addStkDataDaily(finalTempJcjlList, finalTempZyjlList, allInventoryList, finalTradeRecordList,
				finalPkpyList, finalTempThjlList, finalTempXsjlList, finalTempXsjlAbnormalList,
				finalTempXsjlDeleteList, finalTempZyjlDeleteList, finalZyjlChangeList);
		// 修改执行状态
		commonService.UpdateOrInsertStatus(dailyAuditStatus, name, startDate);
		String addDataTimeLog = "新增数据用时：" + (System.currentTimeMillis() - addT) / 1000 + "s";
		String addDataSizeLog = "新增总数据量为：" + (finalTempJcjlList.size() + finalTempZyjlList.size() + allInventoryList.size() +
				finalTradeRecordList.size() + finalPkpyList.size() + finalTempThjlList.size() +
				finalTempXsjlList.size() + finalTempXsjlAbnormalList.size() + finalTempXsjlDeleteList.size() +
				finalTempZyjlDeleteList.size() + finalZyjlChangeList.size());
		log.info(addDataTimeLog + " - " + addDataSizeLog);
		XxlJobHelper.log(addDataTimeLog + " - " + addDataSizeLog);
	}

}

